home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Your Choice 1
/
your choice.zip
/
your choice
/
PRGMMING
/
VISIONIX
/
VAVTIOU.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-12-28
|
31KB
|
1,100 lines
{
════════════════════════════════════════════════════════════════════════════
Visionix Avatar In/Out Driver Unit (VAvtIOu)
Version 0.2
Copyright 1991,92,93 Visionix
ALL RIGHTS RESERVED
────────────────────────────────────────────────────────────────────────────
** revision history in reverse chronological order **
Initials Date Comment
──────── ──────── ────────────────────────────────────────────────────────
jrt 12/23/93 Added documentation.
jrt 11/15/93 Finished out filter.
────────────────────────────────────────────────────────────────────────────
C A V E A T S / K N O W N B U G S
- on the scroll, ra/quick say to scroll the area
1,7,80,25 by one line. we need to validate that the area
we are told to scroll is within the current window.
}
(*-
[SECTION: Section 2: The Text I/O Libraries]
[CHAPTER: Chapter 2: The Avatar Driver & Filter I/O Unit]
[TEXT]
<Overview>
NOTE! This BETA does not include the AVATAR driver procedure.
It will be included in the next BETA!
The VAVTiou unit contains only two procedures: AvatarFilter and
AvatarOutDriverProc. As the names imply, AvatarFilter is a VOUT filter
for Avatar 0+ commands, and AvatarOutDriverProc is an VOUT output driver
for Avatar.
For more information on text filters, drivers, sub-channels, etc., be sure
to read the VOUTu and VINu chapters.
<<The AvatarFilter>>
The Avatar Filter is a VOUT filter procedure. AvatarFilter can be
attached to a VOUT sub-channel via a call to VOutFilterAttach.
After the AvatarFilter has been attached, it will "filter" all of the
Avatar commands in the text-stream sent to that channel, and convert
the Avatar commands one or more "out driver packets", which is the
internal command format used by VOUT.
<<<What the heck does this mean?>>>
Basically it means that after you attach the Avatarfilter to a
sub-channel, you can write Avatar commands into that sub-channel, and
the Avatar commands will be properly interpreted and executed on the
sub-channels display. For example, if you were to attach the Avatar
filter to the sub-channel used by VCRTu, you could then use
Avatar commands in your WRITE and WRITELN statements, and the appropriate
colors, text, actions, etc would appear on your monitor.
<<<Examples and usage>>>
To attach the Avatar filter to the VCRTU's output sub-channel (which is
created automatically in the VCRTu units init-code):
VOutFilterAttach( CrtOCH,
0,
'AvatarFILTER',
'Bx00VMEM',
AvatarFilter,
0,0,0 );
CrtOCH is the channel handle for VCRTus output-channel.
As a paramater to VOutFilterAttach, it tells VOUT which channel
to attach the filter to.
The second parameter, 0, is the flags parameter. AvatarFilter
currently has no flags.
The third parameter, 'AvatarFILTER', is the name by which this
instance of the filter is managed.
The fourth parameter, 'Bx00VMEM', is the name of the sub-channel
off of the "CrtOCH" channel to which the filter should be
attached. 'Bx00VMEM' is the name that VCRTu uses for the default
sub-channel it creates which goes to the primary displays
video memory.
The fifth parameter, AvatarFilter, is the filter procedure to
attach. Since we are attaching the Avatar filter, we specify
the procedure AvatarFilter.
The last three parameters to VOutFilterAttach are parameters/values
which are passed to the AvatarFilter. Currently AvatarFilter has
no parameters, so we leave them all set to 0.
To attach an Avatar filter to a new sub-channel, which happens to use
the Avatar Driver:
{ first we create a new-sub channel off of the CRT output channel }
{ this new-sub channel will use the Avatar output driver procedure. }
{ note that the AvatarOutDriverProc is very different from the }
{ Avatar filter. We'll explain shortly... }
{ part 1 }
VOutSubChannelNew( CrtOCH,
0,
'AvatarOUT',
AvatarOutDriverProc,
caoDOS,0,0 );
{ Then we attach the Avatar filter to the new sub-channel }
{ part 2 }
VOutFilterAttach( CrtOCH,
0,
'AvatarFILTER',
'AvatarOUT', {<--note we specify the new sub-chan name}
AvatarFilter,
0,0,0 );
In "Part 1" of this example we create a new-sub channel. We specify
that this sub-channel will use the AvatarOutDriverProc. The
AvatarOutDriverProc is very different from the AvatarFilter. The
AvatarFilter converts Avatar commands into the "Out driver packets"
used internally within VOUT, and the AvatarOutDriverProc performs
"Out driver Packets" by generating Avatar commands and sending them
to a text-stream output device.
In "Part 2" of this example, we attach the Avatar filter to this
newly created sub-channel.
What we end up with as a result of these actions is a sub-channel
that converts Avatar commands to output driver packets, and then
converts the output-driver packets back into Avatar commands. This
may seem a little uncessarry, but in fact it is not. We need
the intermediate conversion step so that (1) any other filters
which are added to the sub-channel can "understand" the Avatar commands
(since they are now converted to Out driver packets, (2) so that
the Avatar driver (or any other driver we may use) can respond
appropriately. For the Avatar driver, an appropriate response is not
to just send out Avatar commands. It must also "track" everything it
does (IE: keep track of the current text color, current cursor
x/y,etc). By converting the Avatar commands into Out driver
packets, the Avatar driver now has a format by which it can understand
and track the Avatar commands "passing through" it.
How about some simple-english:
Even though this example creates a sub-channel which _generates_
Avatar commands, we still need the Avatar filter to interpret any
Avatar commands sent into the sub-channel by applications which
use VOUT our VCRTu. Why? Because although it may not seem like
it, the easiest way to implement and manage a sub-channel which can
both interpret and generate Avatar commands is to break the two tasks
up into seperate modules: In this case, the AvatarFilter (which
interprets Avatar commands), and the AvatarOutDriverProc (which generates
Avatar commands).
For more information on filter, driver, sub-channels, etc., be sure
to read the VOUTu and VINu chapters.
<<AvatarOutDriverProc>>
The Avatar output-driver procedure is a VOUT output driver. This
output-driver procedure lets you create a sub-channel which will
send Avatar commands to a specified device in response to VOUT text
I/O calls (IE: VOutClrScr, VOutWrite, etc). By default, the
Avatar output-driver sends its output to the local, primary Avatar
device (IE: DOS' Avatar.SYS or OS/2 VIO). However, by specifying
other paramaters when a sub-channel using this driver is created,
Avatar will send its output to any other device, including a VSER
based serial port.
<<<And what does all that mean?>>>
The AvatarOutDriverProc responds to VOUTClrScr, VOutClrEol, VOutWrite,
etc. calls by generating Avatar commands. These Avatar commands can be
sent to Avatar.SYS, OS/2 VIO, a serial port, or just about anywhere you
want by specifying the appropriate parameters on a call to
VOutSubChannelNew. This driver is the key part that allows you,
for example, to use the normal TP CRT API functions (ClrScr, Write,
etc) over the serial port--because VCRTu's CRT API functions work
via VOUT, and VOUT can generate Avatar via this driver!
<<<Examples and usage>>>
To create a new-sub channel which uses the AvatarOutDriverProc
and sends its Avatar output to DOS CON: / Avatar.SYS
{ Here we create a new-sub channel off of the CRT output channel }
{ this new-sub channel will use the Avatar output driver procedure. }
{ part 1 }
VOutSubChannelNew( CrtOCH,
0,
'AvatarOUT',
AvatarOutDriverProc,
caoDOS,0,0 );
CrtOCH is the channel handle for VCRTus output-channel.
As a paramater to VOutSubChannelNew, it tells VOUT which channel
to create a new sub-channel off of.
The second parameter, 0, is the flags parameter. VOutSubChanneNew
currently has no flags.
The third parameter, 'AvatarOUT', is the name by which this
new sub-channel will be managed.
The fourth parameter, AvatarOutDriverProc, is the driver-procedure
which the new sub-channel will use or be "anchored" by. In this
example, we specify AvatarOutDriverProc, which creates a sub-channel
which will generate Avatar commands in response to calls to
VOutClrScr, VOutWrite, VOUTGotoXY, etc.
The last three parameters are parameters which are passed to the
AvatarOutDriverProc.
For the AvatarOutDriverProc, the first of these parameters is a
value which specifies where the Avatar drivers output stream
should be sent. In this example, we specify caoDOS, which tells
the Avatar driver to send its output to the default Avatar device,
which in DOS is CON: (or Avatar.SYS) and in OS/2 is the
VIOWriteTTY function.
When the first of these parameters is caoDOS, the other
two parameters are not used.
To create a new-sub channel which uses the AvatarOutDriverProc
and sends its Avatar output to a custom stream device.
Procedure MySend( Idata : POINTER; Var St : STRING ); Far;
BEGIN
{ write ST to wherever here }
END;
VOutSubChannelNew( CrtOCH,
0,
'CustAvatarOUT',
AvatarOutDriverProc,
caoCustom,
Longint(@MySend),
0 );
CrtOCH is the channel handle for VCRTus output-channel.
As a paramater to VOutSubChannelNew, it tells VOUT which channel
to create a new sub-channel off of.
The second parameter, 0, is the flags parameter. VOutSubChanneNew
currently has no flags.
The third parameter, 'CustAvatarOUT', is the name by which this
new sub-channel will be managed.
The fourth parameter, AvatarOutDriverProc, is the driver-procedure
which the new sub-channel will use or be "anchored" by. In this
example, we specify AvatarOutDriverProc, which creates a sub-channel
which will generate Avatar commands in response to calls to
VOutClrScr, VOutWrite, VOUTGotoXY, etc.
The last three parameters are parameters which are passed to the
AvatarOutDriverProc.
For the AvatarOutDriverProc, the first of these parameters is a
value which specifies where the Avatar drivers output stream
should be sent. In this example, we specify caoCustom, which tells
the Avatar driver to send its output to a custom send-procedure.
When the first of these parameters is caoCustom, the second
parameter should be a pointer to the procedure to call when
AvatarOutDriverProc needs to send out text. Since this
parameter is defined as a longint, this procedure-pointer needs
to be cast to a LONGINT.
When using caoCustom, the third parameter is a 32-bit instance
data value that will be passed to the custom send-procedure.
Every time it is called (This is the IData paramater on the
MySend procedure). You can use this 32-bit value for whatever
you'd like. (IE: as a pointer to other information your
custom send-procedure might need, etc)
For more information on text filters, drivers, sub-channels, etc., be sure
to read the VOUTu and VINu chapters.
<Interface>
-*)
Unit VAvtIOu;
Interface
Uses
VTypesu,
{$IFDEF DEBUG}
VGenu,
VDebugu,
{$endif}
VInlineu,
VStringu,
VOutu;
Procedure AvatarFilter( ODP : POutDriverPacket );
Procedure AttachAvatarFilter( Chan : TChanHandle;
SubChan : STRING );
Implementation
(*-
[FUNCTION]
Procedure AvatarFilter( ODP : POutDriverPacket );
[PARAMETERS]
ODP Pointer to a VOUT Out-driver request packet
[RETURNS]
(None)
[DESCRIPTION]
This procedure is an AVATAR 0+ filter for the Visionix Input/Output
architecture.
This procedure will "filter" incoming AVATAR requests and generate
the appropriate Out-Driver-Packets (ODP), and pass the new ODP
packets down the driver stack of the sub-channel this filter
is attached to.
This procedure should NOT be called directly. Instead, use the
VOutFilterAttach function to attach this filter to a previously
created output sub-channel.
[SEE-ALSO]
(None)
[EXAMPLE]
VOutFilterAttach( TheChan,
0,
'AVT0+filter',
'TheSubChan',
AvatarFilter,
NIL );
-*)
Procedure AvatarFilter( ODP : POutDriverPacket );
Type
TCharBuff = Array[1..32768] of CHAR;
PCharBuff = ^TCharBuff;
TAvatarEmu = RECORD
State : BYTE;
Chars : STRING;
CharsToGet : BYTE;
S : STRING;
END;
PAvatarEmu = ^TAvatarEmu;
TAvatarFilterIData = Record
Off : WORD;
Name : TProcName;
AvatarEMU : TAvatarEMU;
END; { TCRTOutDriverIData }
PAvatarFilterIData = ^TAvatarFilterIData;
{----}
Var
IData : PAvatarFilterIData;
Z : INTEGER;
SBuff : STRING;
testx,testy: INTEGER;
{---------------------------------------------------}
Procedure SBuffFlush;
Var
MyODP : TOutDriverPacket;
BEGIN
If SBuff<>'' Then
BEGIN
MyODP.Func := ODF_WriteBlock;
MyODP.Buff := @SBuff[1];
MyODP.Size := Byte(SBuff[0]);
MyODP.Start := 1;
MyODP.NextDriver := ODP^.NextDriver;
MyODP.Status := 0;
CallNextDriver( @MyODP );
SBuff := '';
END;
END;
{---------------------------------------------------}
Procedure AvatartoODP( TheAvatarEMU : PAvatarEMU;
Ch : CHAR;
OrigODP : POutDriverPacket );
Var
L1 : INTEGER;
L2 : BYTE;
L3 : BYTE;
MyODP : TOutDriverPacket;
aTextAttr : BYTE;
{─────────────────────────────────────────────────────}
Procedure MyWrite( CH: CHAR );
BEGIN
StrAddCh( SBuff, CH );
(*
ODP.Func := ODF_WriteChar;
ODP.CH := CH;
ODP.Status := 0;
CallNextDriver( @ODP );
*)
END;
Procedure MyWriteStr( S : STRING );
Var
Z : INTEGER;
BEGIN
If (Length(Sbuff)+Length(S)) > 255 Then
SBuffFlush;
StrAddStr( SBuff, S );
(*
For Z:=1 to Length( S ) Do
MyWrite( S[Z] );
*)
END;
{─────────────────────────────────────────────────────}
Function MyGetX : INTEGER;
Var
AnOdp : TOutDriverPacket;
BEGIN
AnOdp := MyOdp;
AnODP.Func := ODF_GetXY;
AnODP.Status := 0;
CallNextDriver( @AnODP );
MyGetX := AnODP.X1;
END;
Function MyGetY : INTEGER;
Var
AnOdp : TOutDriverPacket;
BEGIN
AnOdp := MyOdp;
AnODP.Func := ODF_GetXY;
AnODP.Status := 0;
CallNextDriver( @AnODP );
MyGetY := AnODP.Y1;
END;
Const
casStream = 0;
casRepeatChar = 1;
casCtrlV = 2;
casSetAttr = 3;
casGotoXY = 4;
casScrollUp = 5;
casScrollDown = 6;
casClearArea = 7;
casInitArea = 8;
casRepeatString1 = 9;
casRepeatString2 = 10;
casRepeatstring3 = 11;
Var
Z : INTEGER;
BEGIN
{ MyODP := OrigODP^; }
MyODP.NextDriver := OrigODP^.NextDriver;
With TheAvatarEmu^ Do
BEGIN
If CharsToGet>0 Then
BEGIN
StrAddCH( Chars, CH );
Dec(CharsToGet);
END;
If CharsToGet=0 Then
BEGIN
Case State Of
casStream:
BEGIN
Case CH Of
{#8:tab}
^L:
BEGIN
SBuffFlush;
MyODP.Func := ODF_SetAttr;
MyODP.Attr := 3;
MyODP.Status := 0;
CallNextDriver( @MyODP );
MyODP.Func := ODF_ClrScr;
MyODP.Status := 0;
CallNextDriver( @MyODP );
END;
^Y:
BEGIN
Chars := '';
CharsToGet := 2;
State := casRepeatChar;
END;
^V:State := casCtrlV;
ELSE
MyWrite( CH );
END; { case ch of }
END; { state of casStart }
casCtrlV:
BEGIN
Case CH of
^A:State:=casSetAttr;
^B:
BEGIN
SBuffFlush;
MyODP.Func := ODF_GetAttr;
MyODP.Status := 0;
CallNextDriver( @MyODP );
MyODP.Func := ODF_SetAttr;
MyODP.Attr := MyODP.Attr OR $80;
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
^C:
BEGIN
SBuffFlush;
MyODP.Func := ODF_CursorUp;
MyODP.NuMVal := 1;
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
^D:
BEGIN
SBuffFlush;
MyODP.Func := ODF_CursorDown;
MyODP.NuMVal := 1;
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
^E:
BEGIN
SBuffFlush;
MyODP.Func := ODF_CursorLeft;
MyODP.NuMVal := 1;
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
^F:
BEGIN
SBuffFlush;
MyODP.Func := ODF_CursorRight;
MyODP.NuMVal := 1;
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
^G:
BEGIN
SBuffFlush;
MyODP.Func := ODF_ClrEOL;
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
^H:
BEGIN
Chars := '';
CharsToGet := 2;
State := casGotoXY;
END;
^I:
BEGIN
{insert mode}
State := casStream;
END;
^J:
BEGIN
Chars := '';
CharsToGet := 5;
State := casScrollUp;
END;
^K:
BEGIN
Chars := '';
CharsToGet := 5;
State := casScrollDown;
END;
^L:
BEGIN
Chars := '';
CharsToGet := 3;
State := casClearArea;
END;
^M:
BEGIN
Chars := '';
CharsToGet := 4;
State := casInitArea;
END;
^N:
BEGIN
{delete char }
state := casStream;
END;
^Y:
BEGIN
State := casRepeatString1;
{ get the # of chars in the string }
END;
ELSE
State := casStream;
END; { case char after crtl-v of }
END; { casCTRLv }
casSetAttr:
BEGIN
SBuffFlush;
MyODP.Func := ODF_SetAttr;
MyODP.Attr := byte( CH );
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
casGotoXY:
BEGIN
SBuffFlush;
MyODP.Func := ODF_GotoXY;
MyODP.X1 := Byte(chars[2]);
MyODP.Y1 := Byte(chars[1]);
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
casRepeatChar:
BEGIN
S := RepeatString( chars[1], Byte(chars[2] ) );
MyWriteStr( S );
State := casStream;
END;
casRepeatString1:
BEGIN
Chars := '';
CharsToGet := Byte( CH );
State := casRepeatString2;
{ get the string to repeat }
END;
casRepeatString2:
BEGIN
State := casRepeatString3;
{ get the # of times to repeat }
END;
casRepeatString3:
BEGIN
{ do the repeat }
SBuffFlush;
MyODP.Func := ODF_RepeatBlock;
MyODP.NumVal := Byte(CH);
MyODP.Size := Length( Chars );
MyODP.Start := 1;
MyODP.Buff := @chars[1];
MyODP.Status := 0;
CallNextDriver( @MyODP );
(*
For Z:=1 to Byte(CH) Do
MyWriteStr( Chars );
*)
State := casStream;
END;
casScrollUp:
BEGIN
SBuffFlush;
{
For Z:=2 to 5 Do
If Byte(Chars[Z])=0 Then Byte(Chars[Z]):=1;
}
MyODP.Func := ODF_RegionScrUp;
MyODP.NumVal := byte(chars[1]);
MyODP.X1 := byte(chars[3]);
MyODP.Y1 := byte(chars[2]);
MyODP.X2 := byte(chars[5]);
MyODP.Y2 := byte(chars[4]);
{$IFDEF DEBUG}
DebugWriteLn('Avatar Scroll Up');
DebugWriteLn(' Current X ......... '+IntToStr( MyGetX ) );
DebugWriteLn(' Current Y ......... '+IntToStr( MyGetY ) );
DebugWriteLn(' Scroll count ...... '+IntToStr( MyODP.Numval ) );
DebugWriteLn(' X1 ................ '+IntToStr( MyODP.X1 ) );
DebugWriteLn(' Y1 ................ '+IntToStr( MyODP.Y1 ) );
DebugWriteLn(' X2 ................ '+IntToStr( MyODP.X2 ) );
DebugWriteLn(' Y2 ................ '+IntToStr( MyODP.Y2 ) );
{$ENDIF}
{ If MyODP.Y2=25 Then MyOdp.Y2:=24;}
MyODP.Status := 0;
CallNextDriver( @MyODP );
State := casStream;
END;
casScrollDown:
BEGIN
SBuffFlush;
{
For Z:=2 to 5 Do
If Byte(Chars[Z])=0 Then Byte(Chars[Z]):=1;
}
MyODP.Func := ODF_RegionScrDown;
MyODP.NumVal := byte(chars[1]);
MyODP.X1 := byte(chars[3]);
MyODP.Y1 := byte(chars[2]);
MyODP.X2 := byte(chars[5]);
MyODP.Y2 := byte(chars[4]);
MyODP.Status := 0;
{$IFDEF DEBUG}
DebugWriteLn('Avatar Scroll Up');
DebugWriteLn(' Current X ......... '+IntToStr( MyGetX ) );
DebugWriteLn(' Current Y ......... '+IntToStr( MyGetY ) );
DebugWriteLn(' Scroll count ...... '+IntToStr( MyODP.Numval ) );
DebugWriteLn(' X1 ................ '+IntToStr( MyODP.X1 ) );
DebugWriteLn(' Y1 ................ '+IntToStr( MyODP.Y1 ) );
DebugWriteLn(' X2 ................ '+IntToStr( MyODP.X2 ) );
DebugWriteLn(' Y2 ................ '+IntToStr( MyODP.Y2 ) );
{$ENDIF}
CallNextDriver( @MyODP );
State := casStream;
END;
casClearArea:
BEGIN
MyODP.Func := ODF_GetXY;
MyODP.Status := 0;
CallNextDriver( @MyODP );
MyODP.Func := ODF_RegionFill;
MyODP.Attr := byte(chars[1]);
MyODP.Ch := ' ';
MyODP.X2 := Pred(MyODP.X1+byte(chars[3]));
MyODP.Y2 := Pred(MyODP.Y1+byte(chars[2]));
MyODP.Status := 0;
{$IFDEF DEBUG}
DebugWriteLn('Avatar Clear Area');
DebugWriteLn(' Attribute ......... '+IntToHex( MyODP.Attr ) );
DebugWriteLn(' X1 ................ '+IntToStr( MyODP.X1 ) );
DebugWriteLn(' Y1 ................ '+IntToStr( MyODP.Y1 ) );
DebugWriteLn(' X2 ................ '+IntToStr( MyODP.X2 ) );
DebugWriteLn(' Y2 ................ '+IntToStr( MyODP.Y2 ) );
{$ENDIF}
CallNextDriver( @MyODP );
State := casStream;
END;
casInitArea:
BEGIN
MyODP.Func := ODF_GetXY;
MyODP.Status := 0;
CallNextDriver( @MyODP );
MyODP.Func := ODF_RegionFill;
MyODP.Attr := byte(chars[1]);
MyODP.CH := chars[2];
MyODP.X2 := Pred(MyODP.X1+byte(chars[4]));
MyODP.Y2 := Pred(MyODP.Y1+byte(chars[3]));
MyODP.Status := 0;
{$IFDEF DEBUG}
DebugWriteLn('Avatar Init Area');
DebugWriteLn(' Attribute ......... '+IntToHex( MyODP.Attr ) );
DebugWriteLn(' X1 ................ '+IntToStr( MyODP.X1 ) );
DebugWriteLn(' Y1 ................ '+IntToStr( MyODP.Y1 ) );
DebugWriteLn(' X2 ................ '+IntToStr( MyODP.X2 ) );
DebugWriteLn(' Y2 ................ '+IntToStr( MyODP.Y2 ) );
{$ENDIF}
CallNextDriver( @MyODP );
State := casStream;
END;
END; { case state of }
END; { if CharsToGet=0 }
END; { with TheAvatarEmu^ }
END; { Avatar to odp }
{---------------------------------------------------}
BEGIN { CRTOutDriverProc }
IData := ODP^.ID;
If ODP^.Status = 0 Then
BEGIN
Case ODP^.Func Of
ODF_DriverNew:
BEGIN
{-----------------------------}
{ are they telling me to new? }
{-----------------------------}
IF @ODP^.OutDriverProc = @AvatarFilter Then
BEGIN
{-------------------------}
{ Get a new Instance Data }
{ master node. }
{-------------------------}
New( Idata );
IData^.Off := 0;
IData^.Name := ODP^.Name^;
FillChar( Idata^.AvatarEmu, SizeOf(TAvatarEmu), 0 );
ODP^.Status := ODS_Install+ODS_Changed;
ODP^.ID := IData;
END; { If ODP^.OutDriverProc --> Us }
END; { ODF_DriverNew }
{----}
ODF_DriverOff:
BEGIN
If ODP^.Name^ = IData^.Name Then
BEGIN
Inc( Idata^.Off );
END; { If ODP^.Name^ }
END; { ODF_DriverOff }
{----}
ODF_DriverOn:
BEGIN
If ODP^.Name^ = IData^.Name Then
BEGIN
If Idata^.Off <> 0 Then
Dec( Idata^.Off );
END; { ODP^.Name^ }
END; { ODF_DriverOn }
{----}
ODF_DriverDispose:
BEGIN
If ODP^.Name^ = IData^.Name Then
BEGIN
{RemoveFromOutDriverStack }
Dispose( IData );
END; { If ODP^.Name^ }
END; { ODF_DriverDispose }
{----}
ODF_WriteChar:
BEGIN
SBuff := '';
AvatartoODP( @IData^.AvatarEmu,
ODP^.CH,
ODP );
SBuffFlush;
{make sure ODP.func hasnt changed to make us }
{ do another part of the case statement }
END; { ODF_WriteChar }
{----}
ODF_WriteBlock:
BEGIN
SBuff := '';
For Z:=ODP^.Start to ODP^.Size Do
BEGIN
AvatartoODP( @IData^.AvatarEmu,
PCharBuff( ODP^.Buff )^[Z],
ODP );
END; { For Z }
ODP^.Start := ODP^.Size;
SBuffFlush;
END; { ODF_WriteBlock }
{----}
Else { Else Case }
CallNextDriver( ODP );
END; { Case ODP^.Func }
END; { If ODP^.Status = 0 }
END; { AvatarFilter }
Procedure AttachAvatarFilter( Chan : TChanHandle;
SubChan : STRING );
BEGIN
VOutFilterAttach( Chan,
0,
'AVTFILTER',
SubChan,
AvatarFilter,
0,0,0 );
END;
BEGIN
END.